package com.sunshine.scw.base.dao.query;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.FetchMode;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleProjection;

import com.sunshine.scw.base.dao.Pagination;



/**
 * 查询工具类
 * 
 * @author xiao
 * @version 1.0
 */
public class QueryUtil<T> implements Serializable {

	private static final long serialVersionUID = -8109231951611457157L;

	/**
	 * 约束查询类集合对象
	 */
	private List<QueryRestriction> conditions = new ArrayList<QueryRestriction>();

	/**
	 * 投影查询类集合对象
	 */
	private List<QueryProjection> projections = new ArrayList<QueryProjection>();

	/**
	 * 迫切查询类集合对象
	 */
	private List<QueryFetchMode> fetchModes = new ArrayList<QueryFetchMode>();

	/**
	 * 排序查询类集合对象
	 */
	private List<QueryOrder> orders = new ArrayList<QueryOrder>();

	/**
	 * 分页工具类
	 */
	private Pagination<T> pagination;

	/**
	 * 添加排序查询条件
	 */
	public QueryUtil<T> addOrder(QueryOrder order) {
		orders.add(order);
		return this;
	}

	/**
	 * 添加约束查询条件
	 */
	public QueryUtil<T> add(QueryRestriction condition) {
		conditions.add(condition);
		return this;
	}

	/**
	 * 添加迫切查询条件
	 */
	public QueryUtil<T> setFetchMode(QueryFetchMode fetchMode) {
		fetchModes.add(fetchMode);
		return this;
	}

	/**
	 * 添加分页大小和当前页码
	 */
	public QueryUtil<T> addPaginationInfo(int pageNo, int pageSize) {
		this.pagination = new Pagination<T>(pageNo, pageSize);
		return this;
	}

	/**
	 * 得到所有的Criterion条件
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Criterion> criterions() {
		List<Criterion> criterions = new ArrayList<Criterion>();
		for (int i = 0; i < conditions.size(); i++) {
			QueryRestriction cond = conditions.get(i);
			int ioperator = cond.getIoperator();
			if (ioperator == QueryRestriction.OP_OR
					|| ioperator == QueryRestriction.OP_AND) {
				List<QueryRestriction> ors = (List) cond.getValue();
				Criterion tCriterion = null;
				for (int j = 0; j < ors.size(); j++) {
					if (ioperator == QueryRestriction.OP_AND) {
						Conjunction conjunction = Restrictions.conjunction();
						tCriterion = conjunction.add(getCondition(ors.get(j)));
					} else {
						Disjunction disjunction = Restrictions.disjunction();
						tCriterion = disjunction.add(getCondition(ors.get(j)));
					}
				}
				if (null != tCriterion)
					criterions.add(tCriterion);
			} else {
				criterions.add(getCondition(cond));
			}
		}
		return criterions;
	}

	/**
	 * 得到所有的排序条件
	 * 
	 * @return
	 */
	public List<Order> getOrders() {
		List<Order> orderList = new ArrayList<Order>();
		for (QueryOrder queryOrder : orders) {
			int op = queryOrder.getiOrder();
			String property = queryOrder.getProperty();
			switch (op) {
			case QueryOrder.ORDER_ASC:
				orderList.add(Order.asc(property));
				break;
			case QueryOrder.ORDER_DESC:
				orderList.add(Order.desc(property));
				break;
			}
		}
		return orderList;
	}

	/**
	 * 得到所有的投影查询条件
	 * 
	 * @return
	 */
	public List<SimpleProjection> projections() {
		List<SimpleProjection> simpleProjections = new ArrayList<SimpleProjection>();
		for (int i = 0; i < projections.size(); i++) {
			QueryProjection projection = projections.get(i);
			simpleProjections.add(getProjections(projection));
		}
		return simpleProjections;
	}

	/**
	 * 得到所有的迫切条件
	 * 
	 * @return
	 */
	public Map<String, FetchMode> getFetchModes() {
		Map<String, FetchMode> fetchModeMap = new HashMap<String, FetchMode>();
		for (int i = 0; i < fetchModes.size(); i++) {
			QueryFetchMode queryFetchMode = fetchModes.get(i);
			String property = queryFetchMode.getProperty();
			FetchMode fetch = getFetchModes(queryFetchMode);
			if (null != fetch) {
				fetchModeMap.put(property, fetch);
			}
		}
		return fetchModeMap;

	}

	/**
	 * 判断，并封装迫切查询条件
	 * 
	 * @param fetchMode
	 * @return
	 */
	public FetchMode getFetchModes(QueryFetchMode fetchMode) {
		FetchMode fetch = null;
		if (fetchMode == null)
			return null;
		int op = fetchMode.getIoperator();
		switch (op) {
		case QueryFetchMode.DEFAULT:
			fetch = FetchMode.DEFAULT;
			break;
		case QueryFetchMode.JOIN:
			fetch = FetchMode.JOIN;
			break;
		case QueryFetchMode.SELECT:
			fetch = FetchMode.SELECT;
			break;
		}
		return fetch;
	}

	/**
	 * 判断，并封装投影查询条件
	 * 
	 * @param projection
	 * @return
	 */
	public SimpleProjection getProjections(QueryProjection projection) {
		SimpleProjection projections = null;
		if (projection == null)
			return null;
		int op = projection.getOperator();
		String property = projection.getProperty();
		switch (op) {
		case QueryProjection.OP_AVG:
			projections = Projections.avg(property);
			break;
		case QueryProjection.OP_COUNT:
			projections = Projections.count(property);
			break;
		case QueryProjection.OP_COUNT_DISTINCT:
			projections = Projections.countDistinct(property);
			break;
		case QueryProjection.OP_GROUP:
			projections = Projections.groupProperty(property);
			break;
		case QueryProjection.OP_MAX:
			projections = Projections.max(property);
			break;
		case QueryProjection.OP_MIN:
			projections = Projections.min(property);
			break;
		case QueryProjection.OP_SUM:
			projections = Projections.sum(property);
			break;
		}
		return projections;
	}

	/**
	 * 判断，并封装约束条件
	 * 
	 * @param restriction
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Criterion getCondition(QueryRestriction restriction) {
		Criterion cton = null;
		if (null != restriction) {
			int oper = restriction.getIoperator();
			String property = restriction.getProperty();
			Object value = restriction.getValue();
			switch (oper) {
			case QueryRestriction.OP_EQ:
				cton = Restrictions.eq(property, value);
				break;
			case QueryRestriction.OP_LE:
				cton = Restrictions.le(property, value);
				break;
			case QueryRestriction.OP_GT:
				cton = Restrictions.gt(property, value);
				break;
			case QueryRestriction.OP_LT:
				cton = Restrictions.lt(property, value);
				break;
			case QueryRestriction.OP_GE:
				cton = Restrictions.ge(property, value);
				break;
			case QueryRestriction.OP_IS_NULL:
				cton = Restrictions.isNull(property);
				break;
			case QueryRestriction.OP_IS_NOT_NULL:
				cton = Restrictions.isNotNull(property);
				break;
			case QueryRestriction.OP_NE:
				cton = Restrictions.ne(property, value);
				break;
			case QueryRestriction.OP_LIKE:
				cton = Restrictions.like(property, value);
				break;
			case QueryRestriction.OP_ILIKE:
				cton = Restrictions.ilike(property, value.toString(),
						MatchMode.START);
				break;
			case QueryRestriction.OP_NOT_EMPTY:
				cton = Restrictions.isNotEmpty(property);
				break;
			case QueryRestriction.OP_EMPTY:
				cton = Restrictions.isEmpty(property);
				break;
			case QueryRestriction.OP_IN:
				if (value instanceof Object[]) {
					Object[] objs = ((Object[]) value);
					cton = Restrictions.in(property, objs);
				}
				if (value instanceof Collection) {
					Collection collection = ((Collection) value);
					cton = Restrictions.in(property, collection);
				}
				break;
			case QueryRestriction.OP_NOT_IN:
				if (value instanceof Object[]) {
					Object[] objs = ((Object[]) value);
					cton = Restrictions.not(Restrictions.in(property, objs));
				}
				if (value instanceof Collection) {
					Collection collection = ((Collection) value);
					cton = Restrictions.not(Restrictions.in(property,
							collection));
				}
				break;
			}

		}
		return cton;

	}

	public Pagination<T> getPagination() {
		return pagination;
	}

}
